﻿<!DOCTYPE html>
<html>
<head>
<title>Movie Map</title>
<!-- jQuery -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js"></script>
<!-- DataTables -->
<link rel="stylesheet" type="text/css" href="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/css/jquery.dataTables.css">
<!-- Bootstrap -->
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
<!-- Google Maps -->
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?sensor=false"></script>
<link href='http://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700' rel='stylesheet' type='text/css'>
<!-- This page's CSS -->
<link href='style.css' rel='stylesheet' type='text/css'>
<script type="text/javascript">
	var request;
	var tweetTemplate;
	var tableTemplate;
	
	var Map = {
		mapOptions :  {
			zoom : 4,
			center : new google.maps.LatLng(53.598048, 9.931692),
			mapTypeId : google.maps.MapTypeId.ROADMAP
		},
		markers : [],
		addMarker: function(title, tweet, lat, lng) {
			var markerOptions = {
					position : new google.maps.LatLng(lat, lng),
					map : Map.map,
					title : title,
					animation : google.maps.Animation.DROP
			};
			//Check that marker is not yet added
			if ($.inArray(JSON.stringify(arguments), Map.markers) == -1) {
				Map.markers.push(JSON.stringify(arguments));
				var marker = new google.maps.Marker(markerOptions);
				marker.info = new google.maps.InfoWindow({
					content : '<div style="min-width: 400px;"><b>Movie:</b> '
							+ title + "<br>" + '<b>User:</b> ' + tweet.user
							+ "<br>" + '<b>Tweet:</b> ' + tweet.text + "</div>"
				});
				google.maps.event.addListener(marker, 'click', function() {
					Map.closeWindows();
					Map.infoWindow = marker.info;
					Map.infoWindow.open(Map.map, marker);
				});
			}
			},
		showCoordinates :function (event) {
			Map.closeWindows();
		    Map.infoWindow = new google.maps.InfoWindow({
		      position: event.latLng,
		      content: "<b>Position</b>:<br> " +event.latLng.toString().replace(/[)() ]/g,"")
		      			+ ",1000"
		    });
		    Map.circle = new google.maps.Circle({
		    	  map: Map.map,
		    	  radius: 1000000, 
		    	  fillColor: '#AA0000',
		    	  center: event.latLng
		    });
		    google.maps.event.addListener(Map.infoWindow, 'closeclick', Map.closeWindows);
		    Map.infoWindow.open(Map.map);
		},		
		closeWindows: function() {
			if (Map.infoWindow)
				Map.infoWindow.close();
			if(Map.circle)
				Map.circle.setVisible(false);
		},
		showTweet: function(event) {
			event.preventDefault();
			var coords = $(this).data("coords");
			var pos = new google.maps.LatLng(coords[0], coords[1]);
			Map.map.setCenter(pos);
			Map.map.setZoom(12);
			$('#myTab a:first').tab('show');
		},
		displayMovies : function(data) {
			for (i = 0; i < data.length; i++) {
				var tweet = {
					user : data[i].user.name,
					text: data[i].text
				};
				Map.addMarker(data[i].movie, tweet, data[i].coordinates.coordinates[1], data[i].coordinates.coordinates[0]);
			}
		},
		loadData : function() {
			$.get("/movie_tweets", Map.displayMovies);
		},
		ready : function() {
			$("#tweets").on("click", "table .btn", Map.showTweet);
			$('#myTab a:first').on('shown', function() { google.maps.event.trigger(Map.map, "resize") });
			Map.map = new google.maps.Map(document.getElementById("map"), Map.mapOptions);
			Map.addMarker("Ikum", {
				user : "Felix",
				text : "Ask Steffen if you have questions"
			}, 53.598048, 9.931692);
			google.maps.event.addListener(Map.map, 'click', Map.showCoordinates);
			Map.loadData();
		}
	};
	
	var Streaming = {
		streamData : function(limit, keywords, tagged) {
			var params = { limit : limit };
			if(keywords)
				params.keywords = keywords;
			tagged = typeof tagged !== "undefined" ? tagged : true;
			params.tagged = tagged;
			$.post("/stream?" + $.param(params));
		},
		clickStream : function(event) {
			event.preventDefault();
			var keywords = $("#keywords").val();
			var limit = $("#limit-stream").val();
			var tagged = $("#tagged").prop("checked");
			Streaming.streamData(limit, keywords, tagged);
		},
		ready : function() {
			$("#start-stream").click(Streaming.clickStream);
		}
	};

	var Search = {
		loadMovie : function(movie, exact){
			var params = { title : movie };
			if(exact)
				params.exact = true;
			else
				params.exact = !$("#query").is(":focus");
			$.get("/movies?" + $.param(params), function(data) {
				if(data != null) {
					var rendered = Mustache.to_html(Search.template, data);
					$("#movie-data").html(rendered);
				}
			});
		},
		searchPrefix : function() {
			Search.loadMovie($(this).val());
		},
		updateImage : function(data) {
			$("#" + data.name).attr('src', 'images?name=' + data.name + '&nocache=' + (new Date()).getTime());
        },
        comment : function() {
        	$this = $(this);
        	var id = $this.data("id");
        	var comment = $("#"+id+"-comment").html();
        	$.post("/comment?id=" + id, { comment : comment }, function() {
        		$this.addClass(".diable").text("Saved");
        	});
        },
		upload : function() {
            var file = this.files[0];
            var id = $(this).data("id");
            name = file.name;
            var data = new FormData();
            data.append(name, file)
            $.ajax({
                url: '/images?name=' + id,
                type: 'POST',
                success: Table.updateImage,
                data: data,
                contentType: false,
                processData: false
            });
		},
		loadImdbPoster : function(event) {
			event.preventDefault();
			var $this = $(this);
			$.get("http://www.omdbapi.com/?" + $.param({ t : $this.data("title") }), function(data) {
				var importParams = {
					name : $this.data("id"),
					url : data.Poster	
				};
				$.get("/images?" + $.param(importParams), function(data) {
					Search.updateImage(data);
				}).always(function(){
					$this.hide();
				}).error(function() {
					$this.parent().append('<div class="alert"><button type="button" class="close" data-dismiss="alert">&times;</button><strong>Failed.</strong> Poster not found at IMDB.</div>')
				});
			}, "json");
		},
		ready : function() {
			Search.template = $('#movie-template').html();
			$("#movie-data").on("change", 'input[type="file"]', Search.upload);
			$("#movie-data").on("click", '.comment-button', Search.comment);
			$("#movie-data").on("click", '.imdb-poster', Search.loadImdbPoster);
			$("#query").keyup(Search.searchPrefix);
			$("#query").typeahead({
		        source: function(query, process) {
		            $.get('/suggestions?query='+query, function(data) {
		                process(data);
		            });
		        },
		        updater: function(item) {
		        	Search.loadMovie(item, true);
		        	return item;
		        },
		        sorter: function (items) {
		            return items.sort(function(a,b){
			        	return a.length > b.length;
			        });
		        }
		    });
		}
	};

	Table = {
		abortOther : function() {
			if(Table.request)
				Table.request.abort();
		},
		queryMovie : function() {
			Table.abortOther();
			var params = $.param({
				query : $("#parameter").val(),
				limit : $("#limit").val(),
				type : $("#query-type").val()
			});
			Table.request = $.get("/movies?" + params, function(data) {
				data = $.map(data, function(val, i) {
					val.tweetCount = 0;
					if(val.tweets) {
						val.tweetCount = val.tweets.length;
					}
					val.genres = val.genre.join(", ");
					val.runtime = val.runtime.replace("|",", ");
					return val;
				});
				var rendered = Mustache.to_html(Table.tableTemplate, {movies : data });
				$("#table-container").html(rendered);
				Table.tableify("#movie-table");
			});
		},
		queryTweet : function(event){
			Table.abortOther();
			event.preventDefault();
			var params = $.param({
				query : $("#parameter-tweet").val(),
				limit : $("#limit-tweet").val(),
				type : $("#query-type-tweet").val()
			});
			Table.request = $.get("/tweets?" + params, function(data) {
				var rendered = Mustache.to_html(Table.tweetTemplate, {Tweets : data });
				$("#tweet-container").html(rendered);
				Table.tableify("#tweet-table");
			});
		},
		showSearch : function() {
        	var q = $(this).data("title");
        	$("#query").val(q);
        	Search.loadMovie(q);
        	$('#myTab a[href="#search"]').tab('show');
        },
		tableify : function(name) {
			$(name).dataTable({
				"oLanguage": {
						"sSearch": "Filter search results:",
						"sLengthMenu": "Show <select>"+
							"<option value=\"25\">25</option>"+
							"<option value=\"50\">50</option>"+
							"<option value=\"100\">100</option>"+
							"<option value=\"-1\">All</option>"+
							"</select> search results per page"
					},
				"iDisplayLength": 25,
				"sDom": "<\"top\"lf<\"clear\">>rt<\"bottom\"ip><\"clear\">"
			});
		},
		ready : function() {
			$("#parameter, #limit").keyup(Table.queryMovie);
			$("#query-type").change(Table.queryMovie);
			$("#parameter-tweet, #limit-tweet").keyup(Table.queryTweet);
			$("#query-type-tweet").change(Table.queryTweet);
			$("#go-tweet").click(Table.queryTweet);
			$("#table-container").on("click", "table .btn", Table.showSearch);
			
			Table.tableTemplate = $('#table-template').html();
			Table.tweetTemplate = $('#tweet-template').html();
		}
	};
	
	function initialize() {
		Search.ready();
		Streaming.ready();
		Map.ready();
		Table.ready();
		
		//Tabbing
		$('#myTab a').click(function(e) {
			e.preventDefault();
			$(this).tab('show');
		});
	}

	$(initialize);
</script>
</head>
<body>
	<div class="container">

		<div class="masthead">
			<h4 class="muted"><i class="icon-film" style="vertical-align: middle; margin-bottom:4px;"></i> Movie mApp - DIS Task</h4>
			<div class="navbar">
				<div class="navbar-inner">
					<div class="container">
						<ul class="nav">
							<li><a href="http://vsis-www.informatik.uni-hamburg.de/teaching/ss-13/dis/" target="_blank">DIS Website</a></li>
							<li><a href="http://docs.mongodb.org" target="_blank">MongoDB Docs</a></li>
							<li><a href="http://www.10gen.com/reference" target="_blank">MongoDB Cheat Sheets</a></li>
							<li><a href="http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-java-driver/" target="_blank">MongoDB
									Java API</a></li>
							<li><a href="http://docs.mongodb.org/manual/tutorial/" target="_blank">MongoDB Tutorials</a></li>
						</ul>
					</div>
				</div>
			</div>
		</div>

		<!-- Jumbotron -->
		<div class="jumbotron">
			<h1>The Movie mApp</h1>
			<p class="lead">Unveiling the geographic patterns underlying tweets about movies.</p>
			<a class="btn btn-success" href="http://127.0.0.1:28017/" target="_blank">Show Mongo at http://127.0.0.1:28017/</a>
		</div>

		<ul class="nav nav-tabs" id="myTab">
			<li class="active"><a href="#moviemap">Map</a></li>
			<li><a href="#search">Search</a></li>
			<li><a href="#table">Queries</a></li>
			<li><a href="#tweets">Tweets</a></li>
			<li class="pull-right"><a href="#discussion">Discussion</a></li>
		</ul>

		<div class="tab-content">
			<div class="tab-pane active" id="moviemap">
				<div class="row-fluid">
					<div class="span12">
						<div class="btn-group pull-right" id="map-controls">
						  <a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#">
						    Load More Data Onto Map
						    <span class="caret"></span>
						  </a>
						  <ul class="dropdown-menu">
							<li><a href="#"  onclick="Streaming.streamData(500); return false;"  >Stream 500 Tweets in Background</a></li>
							<li><a href="#"  onclick="Map.loadData(true); return false;">Update Data from MongoDB</a></li>
						  </ul>
						</div>
						<h3>Geotagged Tweets about Movies</h3>
						<div class="alert alert-info">
						  <button type="button" class="close" data-dismiss="alert">&times;</button>
						  <strong>Note:</strong> Click on markers to show tweets and click on the map to show coordinates and its 1000km radius.
						</div>
					</div>
				</div>
				<div class="row-fluid">
					<div id="map" class="span12"></div>
				</div>
			</div>
			
			<div class="tab-pane" id="search">
				<div class="row-fluid">
					<div class="span6">
						<h3>Search for Movie and Its Tweets</h3>
						<form class="form-horizontal" action="">
							<div class="control-group">
								<label class="control-label" for="query">Movie </label>
								<div class="controls">
									<input type="text" id="query" autocomplete="off" autofocus="autofocus" placeholder="movie name" class="search-query">
								</div>
							</div>
						</form>
					</div>
					<div class="span6">
						<h3>Stream Tweets in Background</h3>
						<form class="form-horizontal" action="">
							<div class="control-group">
								<label class="control-label" for="keywords">Keywords (comma-separated) </label>
								<div class="controls">
									<textarea rows="5" id="keywords" placeholder="Comma-separated Movie Names"></textarea>
								</div>
							</div>
							<div class="control-group">
								<label class="control-label" for="limit-stream">Total Tweets to Stream </label>
								<div class="controls">
									<input type="text" id="limit-stream" value="100">
								</div>
							</div>
							<div class="control-group">
   								<div class="controls">
									<label class="checkbox">
							        <input type="checkbox" id="tagged"> Only geotagged tweets
							      	</label>
									<button class="btn btn-success" id="start-stream">Start Streaming</button>
								</div>
							</div>
						</form>
					</div>
				</div>
				<div class="row-fluid movie" id="movie-data"></div>
			</div>
			
			<div class="tab-pane" id="table">
				<div class="row-fluid">
					<div class="span12">
					<h3>Query the Movie Database</h3>
						<form class="form-horizontal" action="">
							<div class="control-group">
								<label class="control-label" for="query-type">Query </label>
								<div class="controls">
									<select id="query-type">
										<option value="prefix">Search by Title Prefix</option>
										<option value="rating-greater">Rating Greater</option>
										<option value="genre">Find by Genre (comma separated)</option>
										<option value="geo">Search Movies with Tweets that Contain Keyword</option>
										<option value="tweeted">Find Movies that were subject of a tweet (no param)</option>
									</select>
								</div>
							</div>
							<div class="control-group">
								<label class="control-label" for="parameter">Parameter </label>
								<div class="controls">
									<input type="text" id="parameter" placeholder="parameter taken by the query">
								</div>
							</div>
							<div class="control-group">
								<label class="control-label" for="limit">Result Limit </label>
								<div class="controls">
									<input type="text" id="limit" value="10">
								</div>
							</div>
						</form>
						<hr>
					</div>
				</div>
				<div class="row-fluid">
					<div class="span12" id="table-container">
					</div>
				</div>
			</div>
			
			<div class="tab-pane" id="tweets">
				<div class="row-fluid">
					<div class="span12">
					<h3>Query Tweets</h3>
						<form class="form-horizontal" action="">
							<div class="control-group">
								<label class="control-label" for="query-type-tweet">Query </label>
								<div class="controls">
									<select id="query-type-tweet">
										<option value="fts">Indexed Fulltext Search on Tweets</option>
										<option value="newest">Newest Tweets (no param)</option>
										<option value="geo">Newest Geotagged Tweets (no param)</option>
										<option value="near">Get Tweets Near: lat,lng,radius-in-km</option>
									</select>
									<button id="go-tweet" class="btn btn-success">Go</button>
								</div>
							</div>
							<div class="control-group">
								<label class="control-label" for="parameter-tweet">Parameter </label>
								<div class="controls">
									<input type="text" id="parameter-tweet" placeholder="parameter taken by the query">
								</div>
							</div>
							<div class="control-group">
								<label class="control-label" for="limit-tweet">Result Limit </label>
								<div class="controls">
									<input type="text" id="limit-tweet" value="10">
								</div>
							</div>
						</form>
						<hr>
					</div>
				</div>
				<div class="row-fluid">
					<div class="span12" id="tweet-container">
					</div>
				</div>
			</div>
			
			<div class="tab-pane" id="discussion">
				<div class="row-fluid">
					<div class="span12">
						<h3>Report Bugs, Ask Questions, etc.</h3>
						<div id="disqus_thread"></div>
					    <script type="text/javascript">
					        var disqus_shortname = 'mongodbtask'; 
					        (function() {
					            var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true;
					            dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js';
					            (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq);
					        })();
					    </script>
					</div>
				</div>
			</div>
		</div>
	</div>
	<script type="text/template" id="movie-template">
	<div class="span6">
	<table class="table" id="movie-table-list">
		<tr><th>Title</th><td><strong>{{title}}</strong></td></tr>
		<tr><th>Poster</th><td>
			<button class="pull-right btn btn-info imdb-poster" data-title="{{title}}" data-id="{{_id}}">Import Poster from IMDB</button>
			<img src="images?name={{_id}}" id="{{_id}}"/>
			<form class="form-inline" method="POST" enctype="multipart/form-data">
			<span class="label label-info">Upload:</span>
			<input type="file" data-id="{{_id}}"/>
			</form>
			</td></tr>
		<tr><th>Comment</th><td>
			<div class="alert alert-success"><strong>Editable.</strong> You can edit and save this comment.</div>
			<div id="{{_id}}-comment" class="comment" contenteditable="true">
			{{#comment}}
				{{{comment}}}
			{{/comment}}
			{{^comment}}
				No comment, yet. Click here to type one.
			{{/comment}}
			</div>
			<button class="comment-button pull-right btn btn-info" data-title="{{title}}" data-id="{{_id}}">Save</button>
		</td></tr>
		<tr><th>Year</th><td>{{year}}</td></tr>
		<tr><th>Rating</th><td>{{rating}}</td></tr>
		<tr><th>Votes</th><td>{{votes}}</td></tr>
		<tr><th>Runtime</th><td>{{runtime}} minutes</td></tr>
		<tr><th>Genre</th><td>{{genre}}</td></tr>
		<tr><th>Plot</th><td>{{plot}}</td></tr>
		<tr><th>Actors</th><td><ul>
		{{#actors}}
		<li>{{.}}</li>
		{{/actors}}</ul></td></tr>
		<tr><th>Releases</th><td><ul>
		{{#releases}}
		<li>{{country}} : {{date.$date}}</li>
		{{/releases}}</ul></td></tr>
	</table>
	</div>
	<div class="span6">
	{{#tweets}}
		<p class="triangle-right left"><strong>@{{user}}:</strong> {{text}}</p>
	{{/tweets}}
	</div>
	</script>
	<script type="text/template" id="table-template">
	<table class="table" id="movie-table">
		<thead><tr><th>Title</th><th>Year</th><th>Rating</th><th>Votes</th><th>Genre</th><th>Runtime</th><th>Movie</th><th>Tweets</th><th>More</th></tr></thead>
		<tbody>
		{{#movies}}
		<tr>
		<td><strong>{{title}}</strong></td>
		<td>{{year}}</td>
		<td>{{rating}}</td>
		<td>{{votes}}</td>
		<td>{{genres}}</td>
		<td>{{runtime}}</td>
		<td>{{movie}}</td>
		<td>{{tweetCount}}</td>
		<td><button class="btn btn-success" data-title="{{title}}">Details</button></td>
		</tr>
		{{/movies}}
		</tbody>
	</table>
	</script>
	<script type="text/template" id="tweet-template">
	<table class="table" id="tweet-table">
		<thead><tr><th>User</th><th>Tweet</th><th>Created at</th><th>Coordinates</th></tr></thead>
		<tbody>
		{{#Tweets}}
		<tr>
		<td><strong>{{user.name}}</strong></td>
		<td>{{text}}</td>
		<td>{{created_at}}</td>
		<td class="coordinates"><button data-coords="[{{coordinates.coordinates.1}},{{coordinates.coordinates.0}}]" class="btn">{{coordinates.coordinates}}</button></td>
		</tr>
		{{/Tweets}}
		</tbody>
	</table>
	</script>

	<!-- DataTables -->
	<script type="text/javascript" charset="utf8"
		src="https://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.min.js"></script>
	<!-- Bootstrap -->
	<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.min.js" type="text/javascript"></script>
	<!-- Moment.Js -->
	<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.0.0/moment.min.js" type="text/javascript"></script>
	<!-- Mustache -->
	<script type="text/javascript" charset="utf8" src="http://cdnjs.cloudflare.com/ajax/libs/mustache.js/0.7.2/mustache.min.js"></script>
</body>
</html>